#include "httpconn.h"

bool HttpConn::isET;
std::atomic<int> HttpConn::userCount;
const char* HttpConn::srcDir;

HttpConn::HttpConn()
{
    isClose_ = true;
    fd_ = -1;
    addr_ = {0};
}

HttpConn::~HttpConn()
{
    Close();
}

void HttpConn::init(int fd, sockaddr_in addr)
{
    assert(fd > 0);
    fd_ = fd;
    addr_ = addr;

    readBuffer_.RetrieveAll();
    writeBuffer_.RetrieveAll();

    isClose_ = false;
    userCount++;
    LOG(INFO)
        << "Client[" << fd_
        << "](" << GetIP()
        << ":" << GetPort()
        << " in, userCount:"
        << (int)userCount;
}

void HttpConn::Close()
{
    res.UnmapFile();
    if (!isClose_)
    {
        isClose_ = true;
        userCount--;
        close(fd_);
    }
    LOG(INFO)
        << "Client[" << fd_
        << "](" << GetIP()
        << ":" << GetPort()
        << "out, userCount:"
        << (int)userCount;
}

std::string HttpConn::GetIP()
{
    return inet_ntoa(addr_.sin_addr);
}

int HttpConn::GetPort()
{
    return addr_.sin_port;
}

int HttpConn::GetFd()
{
    return fd_;
}

sockaddr_in HttpConn::GetAddr()
{
    return addr_;
}

ssize_t HttpConn::Read(int *Errno)
{
    ssize_t len = 0;
    do
    {
        len = readBuffer_.ReadFd(fd_, Errno);
        if (len <= 0)
        {
            break;
        }
    } while (isET);
    return len;
}

ssize_t HttpConn::Write(int *Errno)
{
    ssize_t len = 0;
    do
    {
        len = writev(fd_, iov_, iovCnt_);
        if (len <= 0)
        {
            *Errno = errno;
            break;
        }

        if (iov_[0].iov_len + iov_[1].iov_len == 0)
            break;
        else if (len > iov_[0].iov_len)
        {
            iov_[1].iov_base = iov_[1].iov_base + (len - iov_[0].iov_len);
            iov_[1].iov_len -= (len - iov_[0].iov_len);
            if (iov_[0].iov_len)
            {
                writeBuffer_.RetrieveAll();
                iov_[0].iov_len = 0;
            }
        }
        else
        {
            iov_[0].iov_base = iov_[0].iov_base + len;
            iov_[0].iov_len -= len;
            writeBuffer_.Retrieve(len);
        }
    } while (isET || ToWriteByets() > 10240); // TODO ToWriteByets() > 10240
    return len;
}

bool HttpConn::Process()
{
    // 解析请求
    req.Init();
    if (readBuffer_.ReadableBytes() <= 0)
    {
        return false;
    }
    else if (req.Parse(readBuffer_))
    {
        LOG(INFO) << req.GetPath();
        res.Init(srcDir, req.GetPath(), req.IsKeepAlive(), 200);
    }
    else
    {
        res.Init(srcDir, req.GetPath(), false, 400);
    }

    // 设置响应
    res.MakeResponse(writeBuffer_);

    iov_[0].iov_base = writeBuffer_.BeginRead();
    iov_[0].iov_len = writeBuffer_.ReadableBytes();
    iovCnt_ = 1;
    if (res.File() && res.FileLen() > 0)
    {
        iov_[1].iov_base = res.File();
        iov_[1].iov_len = res.FileLen();
        iovCnt_ = 2;
    }

    LOG(INFO) << "file size:" << res.FileLen() << iovCnt_ << " to " << ToWriteByets();

    return true;
}
